package it.trekker.camera;

import it.trekker.db.Photo;
import it.trekker.db.PhotoDAO;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.location.Location;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;
import android.provider.BaseColumns;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import android.util.Log;

public class UtilityCamera {

	private static final String TAG = UtilityCamera.class.getSimpleName();

	private static final String IMG_PREFIX = "TRK_IMG_";
	private static final String VID_PREFIX = "TRK_VID_";
	private static final String STORAGE_DIR = "TrekkerMedia";

	public static final int MEDIA_TYPE_IMAGE = 1;
	public static final int MEDIA_TYPE_VIDEO = 2;


	/** Create a file Uri for saving an image or video */
	public static Uri getOutputMediaFileUri(int type){
		File file = getOutputMediaFile(type);

		if(file != null) 
			return Uri.fromFile(file);
		else
			return null;
	}



	/** Create a File for saving an image or video */
	private static File getOutputMediaFile(int type){
		// To be safe, you should check that the SDCard is mounted
		// using Environment.getExternalStorageState() before doing this.
		File mediaFile = null;

		String storageState = Environment.getExternalStorageState();

		if(storageState.equals(Environment.MEDIA_MOUNTED) && !storageState.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
//			File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), STORAGE_DIR);
			File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), STORAGE_DIR);
			// This location works best if you want the created images to be shared
			// between applications and persist after your app has been uninstalled.

			// Create the storage directory if it does not exist
			if (! mediaStorageDir.exists()) {
				if (! mediaStorageDir.mkdirs()) {
					Log.d(TAG, "failed to create directory");
					return null;
				}
			}

			// Create a media file name
			String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
			if (type == MEDIA_TYPE_IMAGE) {
				mediaFile = new File(mediaStorageDir.getPath() + File.separator + IMG_PREFIX + timeStamp + ".jpg");
			} 
			else if(type == MEDIA_TYPE_VIDEO) {
				mediaFile = new File(mediaStorageDir.getPath() + File.separator + VID_PREFIX + timeStamp + ".mp4");
			} 
			else {
				return null;
			}
		}

		return mediaFile;
	}



	public static boolean launchCamera(Activity parent, Uri fileUri, int requestCode) {
		// create Intent to take a picture and return control to the calling application
		Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

		if(fileUri != null) {
			intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name

			// start the image capture Intent
			parent.startActivityForResult(intent, requestCode);

			return true;
		}

		return false;
	}

	
	public static final int LATITUDE = 0;
	public static final int LONGITUDE = 1;
	
	/**
	 * 
	 * @param value
	 * @param latlong: latitude or longitude
	 * @return
	 */
	private static String[] toDMSFormat(double value, int latlong) {
		
		String[] result = new String[2];
		
		String dms = Location.convert(value, Location.FORMAT_SECONDS);
 		dms = dms.replace(',', '.');
		
		String[] dmsSplitted = dms.split(":");
		String[] degrees = dmsSplitted[0].split("\\.");
		String[] minutes = dmsSplitted[1].split("\\.");
		String[] seconds = dmsSplitted[2].split("\\.");
		
		String degreesNum = degrees[0];
		String degreesDenom = "1";
		if(degrees.length > 1) {
			degreesNum = degrees[0] + degrees[1];
			for(int i = 0 ; i < degrees[1].length() ; i++)
				degreesDenom += "0";
		}

		String minutesNum = minutes[0];
		String minutesDenom = "1";
		if(minutes.length > 1) {
			minutesNum = minutes[0] + minutes[1];
			for(int i = 0 ; i < minutes[1].length() ; i++)
				minutesDenom += "0";
		}
		
		String secondsNum = seconds[0];
		String secondsDenom = "1";
		if(seconds.length > 1) {
			secondsNum = seconds[0] + seconds[1];
			for(int i = 0 ; i < seconds[1].length() ; i++)
				secondsDenom += "0";
		}
		
		result[0] = degreesNum + "/" + degreesDenom + "," + minutesNum + "/" + minutesDenom + "," + secondsNum + "/" + secondsDenom;
		
		Log.d(TAG, "Original: " + dms);
		Log.d(TAG, "Transformed: " + result);
		
		
		// Ref
		
		switch(latlong) {
			case LATITUDE:
				result[1] = (value > 0)? "N" : "S";
				break;
				
			case LONGITUDE:
				result[1] = (value > 0)? "E" : "W";
				break;
				
			default:
				result[1] = "";
				break;
		}
		
		return result;
	} 
	
	
	/**
	 * Convert from a DMS string to a decimal value.
	 * @param value: a string in the format num1/denom1,num2/denom2,num3/denom3
	 * @param latlong: value for latitude or longitude
	 * @return the decimal value corresponding to the value passed
	 */
	public static double dms2decimal(String value, String ref, int latlong) {
		int num;
		int denom;
		double degrees;
		double minutes;
		double seconds;
		
		String[] splitted = value.split(",");
		String[] degreesStr = splitted[0].split("/");
		String[] minutesStr = splitted[1].split("/");
		String[] secondsStr = splitted[2].split("/");
		
		num = Integer.valueOf(degreesStr[0]);
		denom = Integer.valueOf(degreesStr[1]);		
		degrees = (double)num/(double)denom;
		
		num = Integer.valueOf(minutesStr[0]);
		denom = Integer.valueOf(minutesStr[1]);		
		minutes = (double)num/(double)denom;
		
		num = Integer.valueOf(secondsStr[0]);
		denom = Integer.valueOf(secondsStr[1]);		
		seconds = (double)num/(double)denom;
		
		String decimalStr = (int)degrees + ":" + (int)minutes + ":" + seconds;
		
		double decimal = Location.convert(decimalStr);
		
		switch(latlong) {
			case LATITUDE:
				if(ref.equals("S"))
					decimal = -decimal;
				break;
				
			case LONGITUDE:
				if(ref.equals("W"))
					decimal = -decimal;
				break;
		}
		
		return decimal;
		
	}


	public static void storeGeotagInfo(String mediaPath, double latitude, double longitude) {

		String[] latitudeDMS = toDMSFormat(latitude, LATITUDE);
		String[] longitudeDMS = toDMSFormat(longitude, LONGITUDE);
		
		try {
			ExifInterface exif = new ExifInterface(mediaPath);
			exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, latitudeDMS[0]);
			exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, latitudeDMS[1]);
			exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, longitudeDMS[0]);
			exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, longitudeDMS[1]);
			exif.saveAttributes();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}



	public static int deleteImageFromDCIM(Activity parent, String uriImgToPreserve) {

		final String[] imageColumns = { BaseColumns._ID, MediaColumns.DATA };
		final String imageOrderBy = BaseColumns._ID + " DESC";

		Cursor imageCursor = parent.managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, null, null, imageOrderBy);

		if(imageCursor.moveToFirst()) {
			int id = imageCursor.getInt(imageCursor.getColumnIndex(BaseColumns._ID));
			String fullPath = imageCursor.getString(imageCursor.getColumnIndex(MediaColumns.DATA));

			String datetimeDel = "-";
			String datetimePreserve = "-";
			try {
				ExifInterface exifPreserve = new ExifInterface(uriImgToPreserve);
				datetimePreserve = exifPreserve.getAttribute(ExifInterface.TAG_DATETIME);

				ExifInterface exifDel = new ExifInterface(fullPath);
				datetimeDel = exifDel.getAttribute(ExifInterface.TAG_DATETIME);
			} catch (IOException e) {
				e.printStackTrace();
			}


			Log.d(TAG, "img to delete::id " + id);
			Log.d(TAG, "img to delete::path " + fullPath);
			Log.d(TAG, "img to delete::datetimeDel " + datetimeDel);
			Log.d(TAG, "img to preserve::datetimePreserve " + uriImgToPreserve);
			Log.d(TAG, "img to preserve::datetimePreserve " + datetimePreserve);


			imageCursor.close();

			if(datetimeDel != null && datetimePreserve != null) {
				if(datetimeDel.equals(datetimePreserve))
					parent.getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, BaseColumns._ID + "=" + id, null);
			}

			return id;
		}
		else {
			return 0;
		}

	}
	
	
	public static void updateGallery(Activity parent) {
		parent.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"
	            + Environment.getExternalStorageDirectory()))); 
	}
	
	
	public static void savePhotoIntoDatabase(Context ctx, int excursionId, Uri fileUri, Location location) {
		PhotoDAO photoDAO = new PhotoDAO(ctx);
		photoDAO.open();
		Photo photo = new Photo(fileUri.getPath(), excursionId);
		photo.setLatitude(location.getLatitude());
		photo.setLongitude(location.getLongitude());
		photo.setId(photoDAO.insertPhoto(photo));
		photoDAO.close();
	}

}
